package whf.framework.web.tag;

import java.util.List;

import javax.servlet.jsp.JspException;

import whf.framework.entity.TreeNode;
import whf.framework.entity.ext.TreeItem;
import whf.framework.exception.ServiceNotFoundException;
import whf.framework.ext.entity.MenuItem;
import whf.framework.ext.service.MenuItemServiceImp;
import whf.framework.ext.tag.TreeStyle;
import whf.framework.resource.msg.Messages;
import whf.framework.security.UserContext;
import whf.framework.service.TreeService;
import whf.framework.util.BeanFactory;
import whf.framework.util.StringUtils;
import whf.framework.web.WebContextHolder;

/**
 * @author wanghaifeng
 * @create May 6, 2006 9:25:19 PM
 * 
 */
public class TreeTag extends HtmlTag{
	private final static long serialVersionUID = 0;
	
	private final static int DEFAULT_DEEPTH = 100;
	
	/**
	 * WebFxTree:一种树,但是不能包含webFXTree
	 * tree:树型菜单
	 * treeBlock:树状块型菜单
	 * menu:下拉菜单
	 */
	private String displayStyle;
	
	private TreeStyle treeStyle;
	
	private boolean hideRoot = true;
	
	private TreeNode root;
	
	private String treeTitle;

	private Object treeService;
	
	private String param = "treeItemId";
	
	private String parentParam = "treeItemParentId";
	
	private int deepth = DEFAULT_DEEPTH;
	
	private String target="";
	
	private String uri;
	
	private boolean cacheData;
	
	/**
	 * 查询字符串，用于过滤
	 */
	private String queryString;
	
	private boolean rootEventEnabled;
	
	public void setDisplayStyle(String displayStyle) {
		this.displayStyle = displayStyle;
	}
	
	public void setHideRoot(boolean hide){
		this.hideRoot = hide;
	}
	
	public void setRoot(TreeNode root){
		this.root = root;
	}

	public void setRootEventEnabled(boolean rootEventEnabled) {
		this.rootEventEnabled = rootEventEnabled;
	}

	public void setTreeService(Object menuFinder) {
		this.treeService = menuFinder;
	}

	public void setTarget(String target){
		if(target == null){
			return ;
		}
		this.target = target;
	}
	
	public void setTreeStyle(String style) {
		if(StringUtils.equalsIgnoreCase(style, "radio")){
			this.treeStyle = TreeStyle.RADIO;
		} else if(StringUtils.equalsIgnoreCase(style,"checkbox")){
			this.treeStyle = TreeStyle.CHECKBOX;
		} else {
			this.treeStyle = TreeStyle.TEXT;
		}
	}

	public void setParam(String treeParamName) {
		if(StringUtils.isEmpty(treeParamName)) return;
		this.param = treeParamName;
	}

	public void setParentParam(String treeParentParamName) {
		if(StringUtils.isEmpty(treeParentParamName)) return ;
		this.parentParam = treeParentParamName;
	}

	public void setDeepth(int deepth) {
		this.deepth = deepth;
	}

	public void setUri(String uri){
		this.uri = uri;
	}
	
	public void setQueryString(String query){
		this.queryString = query;
	}
	
	public void setTreeTitle(String title){
		this.treeTitle = title;
	}
	
	public void setCacheData(boolean b){
		this.cacheData = b;
	}
	
	private TreeService getTreeService() throws ServiceNotFoundException{
		if(this.treeService != null){
			if(this.treeService instanceof TreeService){
				return (TreeService)this.treeService;
			} else if(this.treeService instanceof String){
				return (TreeService)BeanFactory.getService((String)this.treeService);
			}
		}
		return MenuItemServiceImp.getMenuItemService();
	}
	
	@Override
	public int doStartTag() throws JspException {
		UserContext userContext = WebContextHolder.getWebContext(request()).getUserContext();
		//
		TreeItem treeItem = null;
		try{
			TreeService service = this.getTreeService();
			String id = "Tree:" + service.getClass().getName();
			if(!StringUtils.isEmpty(this.queryString)){
				id += "#" + this.queryString;
			}
			id += "@" + TreeItem.class.getName();
			if(id != null && this.cacheData){
				treeItem = (TreeItem)userContext.getSessionObject(id);
			}
			if(treeItem == null){
				try{
					treeItem = new TreeItem(this.root, service, this.queryString, -1);
				}catch(Exception e){
					log.error(this, e);
				}
				if(this.cacheData && (treeItem != null || id != null)){
					userContext.setSessionObject(id, treeItem);
				}
			}
		}catch(Exception e){
			log.error(this, e);
			throw new JspException("Fetch data exception!", e);
		}
		//
		if(StringUtils.equalsIgnoreCase(this.displayStyle, "WebFxTree")){
			outputWebFxTree(treeItem);
		}
		super.flush();
		return SKIP_BODY;
	}
	
	@Override
	public int doEndTag() throws JspException {
		this.release();
		super.flush();
		return EVAL_PAGE;
	}
	//WebFxTree
	private void outputWebFxTree(TreeItem treeItem) throws JspException{
		for(int i=0;i<4;i++){
			println(Messages.getString("WebFxTree_"+i, request().getContextPath()));
		}
		println("<script type='text/javascript'>");
		for(int i=0;i<=13;i++){
			println(Messages.getString("WebFxTreeConfig_"+i, request().getContextPath()));
		}
		if(this.hideRoot){ //从根结点的一级子节点打印
			List<TreeItem> roots = treeItem.getChildren();
			for(TreeItem root : roots){
				writeWebFxTreeMenuItems(root, 1);
				println("document.write(m"+ root.getId() +");");
			}
		} else { //从根结点开始打印
			long rootId = 0;
			if(this.root != null) rootId = this.root.getId();
			writeWebFxTreeMenuItems(treeItem, 0);
			println("document.write(m"+ rootId +");");
		}
		println("</script>");
	}
	
	private String getRedirectUrl(TreeItem node){
		TreeNode treeItem = node.getTreeItem();
		if(!StringUtils.isEmpty(this.uri)){
			uri = StringUtils.wrapHyperLink(request(), this.uri);
			if(uri.indexOf("?") < 0) uri += "?";
			if(!uri.endsWith("?") && !uri.endsWith("&")) uri +="&";
		}
		if(treeItem == null){
			if(uri == null) uri = "";
			return uri+param+"=0&"+this.parentParam+"=0";
		} else if(!StringUtils.isEmpty(uri)){
			String url = uri+param+"="+treeItem.getId();
			if(treeItem.getParent() != null){
				url += "&"+this.parentParam+"="+treeItem.getParent().getId();
			}
			return url;
		} else if(treeItem instanceof MenuItem && !StringUtils.isEmpty(((MenuItem)treeItem).getHref())){
			return "Menu?type=menu&id="+treeItem.getId();
		} else {
			return "";
		}
	}
	
	/**
	 * 打印一个节点
	 * @param parent 当前打印节点的父节点
	 * @param node 当前打印的节点
	 * @param deepth
	 * @throws JspException
	 */
	private void writeWebFxTreeMenuItems(TreeItem node, int startDeepth) throws JspException{
		if(node.getDeepth() > this.deepth) return;
		try{
			List<TreeItem> children = node.getChildren();
			TreeNode parent = node.getParent();
			
			long menuId = 0;
			String menuName = this.treeTitle;
			String url ="";
			boolean checked = false;
			if(node != null && node.getId() > 0){
				menuId = node.getId();
				menuName = node.getName();
			}
			url = getRedirectUrl(node);
			if(node.getDeepth() == startDeepth){ // 深度为0的为根结点
				if(!this.rootEventEnabled) url = "";
				println("var m"+menuId+" = new WebFXTree('"+menuName+"','"+url+"',m"+menuId+");");
			}else{
				long parentId = 0;
				if(parent != null && parent.getId() > 0){
					parentId = parent.getId();
				}
				if(children.isEmpty()){
					println("var m"+menuId+"=new WebFXTreeItem('"+menuName+"','"+url+"', m"+parentId+",webFXTreeConfig.fileIcon, webFXTreeConfig.fileIcon);");
				}else{
					println("var m"+menuId+"=new WebFXTreeItem('"+menuName+"','"+url+"', m"+parentId+",webFXTreeConfig.folderIcon, webFXTreeConfig.folderIcon);");
				}
			}
			println("m"+menuId+".target='"+target+"';");
			if(this.treeStyle == TreeStyle.CHECKBOX){
				println("m"+menuId+".type='checkbox';");
				println("m"+menuId+".checked="+checked+";");
			} else if(this.treeStyle == TreeStyle.RADIO){
				println("m"+menuId+".radio=true;");
				println("m"+menuId+".checked="+checked+";");
			}
			for(TreeItem child: children){
				writeWebFxTreeMenuItems(child, startDeepth);
			}
		}catch(Exception e){
			log.debug(this, e);
			throw new JspException(Messages.getString("exception.service_not_found", this.treeService));
		}
	}
	
	public void release(){
		super.release();
		this.displayStyle = null;
		this.treeService = null;
		this.root = null;
		this.target = null;
		this.hideRoot = true;
		this.treeStyle = TreeStyle.TEXT;
		this.deepth = DEFAULT_DEEPTH;
		this.param = "treeItemId";
		this.parentParam = "treeItemParentId";
		this.cacheData = false;
	}
}
